package top.syfy.jwt.jwtdemo.redis;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * 针对RedisTemplate的封装类, 为了降低RedisTemplate模板操作的复杂度
 *
 * @author syfy
 * @date 2021/03/07
 */
@SuppressWarnings({"all"})
@Component
public class RedisProvide {

	@Autowired
	private RedisTemplate<String, Object> redisTemplate;

	/* ======================Redis数据的公共操作部分====================== */

	/**
	 * 指定给定的键代表的键值对的缓存失效时间(单位:秒)
	 *
	 * @param key  给定的代表的键值对的键
	 * @param time 缓存失效时间(单位:秒)
	 * @return 设置结果
	 */
	public boolean expire(String key, long time) {
		try {
			if (time > 0) {
				redisTemplate.expire(key, time, TimeUnit.SECONDS);
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 根据给定的key获取其代表的键值对的过期时间(单位:秒)
	 *
	 * @param key 给定的代表的键值对的键
	 * @return 给定的key获取其代表的键值对的过期时间(单位 : 秒), -1代表键不存在
	 */
	public long getExpire(String key) {
		Long result = redisTemplate.getExpire(key, TimeUnit.SECONDS);
		return result == null ? -1L : result;
	}

	/**
	 * 判断key是否存在
	 *
	 * @param key 给定的代表的键值对的键
	 * @return 给定的key的存在状态: true-存在,false-不存在
	 */
	public boolean hasKey(String key) {
		try {
			return Boolean.TRUE.equals(redisTemplate.hasKey(key));
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 根据key删除其对应的代表的键值对
	 *
	 * @param key 给定的代表的键值对的键(可以是集合)
	 */
	public void del(String... key) {
		if (!CollectionUtils.isEmpty(Arrays.asList(key))) {
			redisTemplate.delete(Arrays.asList(key));
		}
	}

	/* ======================Redis数据类型(String)操作部分====================== */

	/**
	 * 字符串缓存获取
	 *
	 * @param key 键
	 * @return 与给定键对应的值
	 */
	public Object get(String key) {
		return key == null ? null : redisTemplate.opsForValue().get(key);
	}

	/**
	 * 字符串缓存存放
	 *
	 * @param key   键
	 * @param value 值
	 * @return 存放结果: true-存放成功,false-存放失败
	 */
	public boolean set(String key, Object value) {
		try {
			redisTemplate.opsForValue().set(key, value);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 字符串缓存存放并设置有效时间
	 *
	 * @param key   键
	 * @param value 值
	 * @param time  有效时间(单位:秒): 若值大于0则代表指定有效时间,若值小于0则代表无限期
	 * @return 存放结果: true-存放成功,false-存放失败
	 */
	public boolean set(String key, Object value, long time) {
		try {
			/*if (time > 0L) {
				redisTemplate.opsForValue().set(key, value, time ,TimeUnit.SECONDS);
			} else {
				redisTemplate.opsForValue().set(key, value);
			}*/
			set(key, value);
			if (time > 0L) {
				expire(key, time);
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 按给定的递增因子进行新增并返回
	 *
	 * @param key   键
	 * @param delta 递增因子
	 * @return 按给定的递增因子进行新增得到的值
	 */
	public long incrBy(String key, long delta) {
		if (delta < 0L) {
			throw new RuntimeException("递增因子必选大于0");
		}
		Long incrResult = redisTemplate.opsForValue().increment(key, delta);
		return incrResult == null ? Long.valueOf(key) : incrResult;
	}

	/**
	 * 按给定的递增因子进行递减并返回
	 *
	 * @param key   键
	 * @param delta 递减因子
	 * @return 按给定的递减因子进行递减得到的值
	 */
	public long decrBy(String key, long delta) {
		if (delta < 0L) {
			throw new RuntimeException("递减因子必选大于0");
		}
		Long decrResult = redisTemplate.opsForValue().decrement(key, delta);
		return decrResult == null ? Long.valueOf(key) : decrResult;
	}

	/* ======================Redis数据类型(Hash)操作部分====================== */

	/**
	 * 从hash表中获取与给定hash键匹配的hash值
	 *
	 * @param key     hash表名称
	 * @param hashKey hash键
	 * @return hash表中获取与给定hash键匹配的hash值
	 */
	public Object hget(String key, String hashKey) {
		return redisTemplate.opsForHash().get(key, hashKey);
	}

	/**
	 * 向hash表中存放单个缓存
	 *
	 * @param key       hash表名称
	 * @param hashKey   hash键
	 * @param hashValue hash值
	 * @return 存放结果: true-存放成功,false存放失败
	 */
	public boolean hset(String key, String hashKey, Object hashValue) {
		try {
			redisTemplate.opsForHash().put(key, hashKey, hashValue);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 向hash表中存放单个缓存并设置有效时间
	 *
	 * @param key       hash表名称
	 * @param hashKey   hash键
	 * @param hashValue hash值
	 * @param time      有效时间(单位:秒): 若值大于0则代表指定有效时间,若值小于0则代表无限期
	 * @return 存放结果: true-存放成功,false存放失败
	 */
	public boolean hset(String key, String hashKey, Object hashValue, long time) {
		try {
			/* redisTemplate.opsForHash().put(key, hashKey, hashValue); */
			hset(key, hashKey, hashValue);
			if (time > 0L) {
				expire(key, time);
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 从hash表中获取所有的键
	 *
	 * @param key hash表名称
	 * @return hash表中所有的键值
	 */
	public Map<Object, Object> hmget(String key) {
		return redisTemplate.opsForHash().entries(key);
	}

	/**
	 * 向hash表中存放java.util.Map缓存集合
	 *
	 * @param key hash表名称
	 * @param map java.util.Map缓存集合
	 * @return 存放结果: true-存放成功,false存放失败
	 */
	public boolean hmset(String key, Map<Object, Object> map) {
		try {
			redisTemplate.opsForHash().putAll(key, map);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 向hash表中存放java.util.Map缓存集合并设置有效时间
	 *
	 * @param key  hash表名称
	 * @param map  java.util.Map缓存集合
	 * @param time 有效时间(单位:秒): 若值大于0则代表指定有效时间,若值小于0则代表无限期
	 * @return 存放结果: true-存放成功,false存放失败
	 */
	public boolean hmset(String key, Map<Object, Object> map, long time) {
		try {
			/* redisTemplate.opsForHash().putAll(key, map); */
			hmset(key, map);
			if (time > 0L) {
				expire(key, time);
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 删除hash表中的给定的键(可以是数组)及其对应的值
	 *
	 * @param key  hash表名称
	 * @param item 给定的键(数组)
	 */
	public void hdel(String key, Object... item) {
		redisTemplate.opsForHash().delete(key, item);
	}

	/**
	 * 判断hash表中是否有给定的键
	 *
	 * @param key     hash表名称
	 * @param hashKey 给定的键名称
	 * @return 存在的状态: true-存在,false-不存在
	 */
	public boolean hHasKey(String key, String hashKey) {
		return Boolean.TRUE.equals(redisTemplate.opsForHash().hasKey(key, hashKey));
	}

	/**
	 * 按给定的递增因子进行新增并返回
	 *
	 * @param key     hash表名称
	 * @param hashKey 键名称
	 * @param delta   递增因子
	 * @return 按给定的递增因子进行新增得到的值
	 */
	public double hIncrBy(String key, String hashKey, double delta) {
		if (delta < 0L) {
			throw new RuntimeException("递增因子必选大于0");
		}
		return redisTemplate.opsForHash().increment(key, hashKey, delta);
	}

	/**
	 * 按给定的递增因子进行递减并返回
	 *
	 * @param key   键
	 * @param delta 递减因子
	 * @return 按给定的递减因子进行递减得到的值
	 */
	public double hDecrBy(String key, String hashKey, double delta) {
		if (delta < 0L) {
			throw new RuntimeException("递减因子必选大于0");
		}
		return redisTemplate.opsForHash().increment(key, hashKey, delta * (-1.0D));
	}

	/* ======================Redis数据类型(Set)操作部分====================== */

	/**
	 * 根据给定的键获取集合中的所有成员
	 *
	 * @param key 键
	 * @return 给定的键代表的集合中的所有成员构成的Set集合
	 */
	public Set<Object> sGet(String key) {
		return redisTemplate.opsForSet().members(key);
	}

	/**
	 * 将数据存入Set缓存
	 *
	 * @param key          Set集合名称
	 * @param memberValues 存入的数据(数组)
	 * @return 存入数据成功的个数
	 */
	public long sSet(String key, Object... memberValues) {
		Long result = redisTemplate.opsForSet().add(key, memberValues);
		return result == null ? 0L : result;
	}

	/**
	 * 将数据存入Set缓存
	 *
	 * @param key          Set集合名称
	 * @param time         有效时间(单位:秒): 若值大于0则代表指定有效时间,若值小于0则代表无限期
	 * @param memberValues 存入的数据(数组)
	 * @return 存入数据成功的个数
	 */
	public long sSet(String key, long time, Object... memberValues) {
		Long result = redisTemplate.opsForSet().add(key, memberValues);
		if (time > 0L) {
			expire(key, time);
		}
		return result == null ? 0L : result;
	}

	/**
	 * 在给定集合中查询指定成员值是否存在
	 *
	 * @param key         集合名称
	 * @param memberValue 指定成员值
	 * @return 存在状态: true-存在,false-不存在
	 */
	public boolean sHasKey(String key, Object memberValue) {
		return Boolean.TRUE.equals(redisTemplate.opsForSet().isMember(key, memberValue));
	}

	/**
	 * 获取Set缓存的长度(Set成员数量)
	 *
	 * @param key Set集合名称
	 * @return Set缓存的长度(Set成员数量)
	 */
	public long sGetSetSize(String key) {
		Long result = redisTemplate.opsForSet().size(key);
		return result == null ? 0L : result;
	}

	/**
	 * 移除Set集合中值(数组)
	 *
	 * @param key          Set集合名称
	 * @param memberValues 移除的值(数组)
	 * @return 成功移除的值的数量
	 */
	public long setRemove(String key, Object... memberValues) {
		Long result = redisTemplate.opsForSet().remove(key, memberValues);
		return result == null ? 0L : result;
	}

	/* ======================Redis数据类型(List)操作部分====================== */

	/**
	 * 返回列表中索引为的元素
	 *
	 * @param key   列表名称
	 * @param index 索引
	 * @return 列表中索引为的元素
	 */
	public Object IGet(String key, long index) {
		return redisTemplate.opsForList().index(key, index);
	}

	/**
	 * 返回列表中索引在[start, stop]中的元素（包括边界值）
	 *
	 * @param key   列表名称
	 * @param start 开始索引
	 * @param end   结束索引
	 * @return 列表中索引在[start, stop]中的元素（包括边界值）
	 */
	public List<Object> IGetRange(String key, long start, long end) {
		return redisTemplate.opsForList().range(key, start, end);
	}

	/**
	 * 将元素放入列表中(尾部)
	 *
	 * @param key   列表名称
	 * @param value 元素
	 * @return 存放操作的结果: true-成功,false-失败
	 */
	public boolean lSet(String key, Object value) {
		try {
			redisTemplate.opsForList().rightPush(key, value);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 将元素列表放入指定列表中(尾部)
	 *
	 * @param key    指定列表名称
	 * @param values 元素列表
	 * @return 存放操作的结果: true-成功,false-失败
	 */
	public boolean lSet(String key, List<Object> values) {
		try {
			redisTemplate.opsForList().rightPushAll(key, values);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 将元素放入列表中(尾部)并设置有效期
	 *
	 * @param key   列表名称
	 * @param value 元素
	 * @param time  有效时间(单位:秒): 若值大于0则代表指定有效时间,若值小于0则代表无限期
	 * @return 存放操作的结果: true-成功,false-失败
	 */
	public boolean lSet(String key, Object value, long time) {
		try {
			lSet(key, value);
			if (time > 0) {
				expire(key, time);
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 将元素列表放入指定列表中(尾部)并设置有效期
	 *
	 * @param key    列表名称
	 * @param values 元素列表
	 * @param time   有效时间(单位:秒): 若值大于0则代表指定有效时间,若值小于0则代表无限期
	 * @return 存放操作的结果: true-成功,false-失败
	 */
	public boolean lSet(String key, List<Object> values, long time) {
		try {
			lSet(key, values);
			if (time > 0) {
				expire(key, time);
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 获取列表的长度(列表元素数量)
	 *
	 * @param key 列表名称
	 * @return 列表的长度(列表元素数量)
	 */
	public long lGetListSize(String key) {
		Long result = redisTemplate.opsForList().size(key);
		return result == null ? 0L : result;
	}

	/**
	 * 根据索引修改列表指定索引的元素
	 *
	 * @param key   列表名称
	 * @param index 索引
	 * @param value 新值
	 * @return 修改操作的结果: true-成功,false-失败
	 */
	public boolean lUpdateIndex(String key, long index, Object value) {
		try {
			redisTemplate.opsForList().set(key, index, value);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 移除列表中前指定数量的指定的值
	 *
	 * @param key   列表名称
	 * @param count 数量
	 * @param value 指定的值
	 * @return 成功移除的元素的数量
	 */
	public long lRemove(String key, long count, Object value) {
		Long result = redisTemplate.opsForList().remove(key, count, value);
		return result == null ? 0L : result;
	}

}
